﻿using common.api.models;
using common.exceptions;
using common.helpers;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using webserver.core;

namespace bookmark.mgr.Controllers.Lv0
{
    public class HomeController
    {
        public HttpResponseActionModel Index(ControllerOption option, string args, HttpRequestModel httpRequest)
        {
            var rsp = ResponseBase<object>.Failed2();
            try
            {
                var body = HttpUtility.UrlDecode(httpRequest.Body);
                switch (args.ToLower())
                {
                    default:
                        {
                            throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, $"无效的参数：{args}");
                        }
                    case "apis":
                        {
                            rsp.data = Apis();
                        }
                        break;
                    case "import":
                        {
                            var request = SerializationHelper.ParseFromQueryString<ImportRequest>(body);
                            rsp.data = Import(request);
                        }
                        break;
                    case "export":
                        {
                            rsp.data = Export(option.WWWRoot);
                        }
                        break;
                    case "download":
                        {
                            var request = SerializationHelper.ParseFromQueryString<DownloadRequest>(httpRequest.Url);
                            var fullName = Path.Combine(option.WWWRoot, "Exports", request.Module, request.FileName);
                            if (!File.Exists(fullName))
                            {
                                var downloadTemplateFullName = Path.Combine(option.WWWRoot, "download.html");
                                if (!File.Exists(downloadTemplateFullName))
                                {
                                    throw new WithCodeException((int)ErrorCodeEnum.CodeError, "请先配置下载页", "请先配置download.html");
                                }

                                var downloadTemplate = File.ReadAllText(downloadTemplateFullName, Encoding.UTF8);
                                downloadTemplate = downloadTemplate.Replace("@@(title)", "下载中...");
                                downloadTemplate = downloadTemplate.Replace("@@(message)", "文件不存在或者正在生成，请稍候刷新页面...");
                                return new HttpResponseActionModel
                                {
                                    ContentType = "text/html",
                                    Text = downloadTemplate,
                                    BodyLength = Encoding.UTF8.GetBytes(downloadTemplate).Length
                                };
                            }
                            else
                            {
                                var bytes = File.ReadAllBytes(fullName);
                                return new HttpResponseActionModel
                                {
                                    ContentType = "application/octet-stream",
                                    Blob = bytes,
                                    BodyLength = bytes.Length,
                                    DownloadFileName = request.FileName,
                                    DownloadFileNameUTF8 = request.FileName
                                };
                            }
                        }
                    case "list":
                        {
                            var request = SerializationHelper.ParseFromQueryString<GetBookmarksRequest>(body);
                            rsp.data = GetBookmarks(request);
                        }
                        break;
                    case "del":
                        {
                            var request = SerializationHelper.ParseFromQueryString<DeleteBookmarksRequest>(body);
                            rsp.data = DeleteBookmarks(request);
                        }
                        break;
                    case "delinvalids":
                        {
                            var request = SerializationHelper.ParseFromQueryString<DeleteBookmarksRequest>(body);
                            rsp.data = DeleteInvalids(request);
                        }
                        break;
                    case "delduplicate":
                        {
                            rsp.data = DeleteDuplicate();
                        }
                        break;
                    case "refresh":
                        {
                            var request = SerializationHelper.ParseFromQueryString<DeleteBookmarksRequest>(body);
                            rsp.data = Refresh(request);
                        }
                        break;
                    case "reset":
                        {
                            var request = SerializationHelper.ParseFromQueryString<DeleteBookmarksRequest>(body);
                            rsp.data = Reset(request);
                        }
                        break;
                }

                rsp.error_code = null;
                rsp.error_message = null;
                rsp.error_message_debug = null;
            }
            catch (WithCodeException wcex)
            {
                rsp.error_code = wcex.Code;
                rsp.error_message = wcex.Message;
            }
            catch (Exception ex)
            {
                LogHelper.WriteAsync(ex.ToString());
            }

            var content = SerializationHelper.ToJson(rsp);
            var contentLength = Encoding.UTF8.GetBytes(content).Length;
            return new HttpResponseActionModel
            {
                ContentType = "application/json",
                Text = content,
                BodyLength = contentLength
            };
        }

        private List<ApiItem> Apis()
        {
            var items = new List<ApiItem>
            {
                new ApiItem { Title="导入书签", Url="/import" },
                new ApiItem { Title="导出书签", Url="/export" },
                new ApiItem { Title="书签列表", Url="/bookmarks" }
            };
            return items;
        }

        private string Import(ImportRequest request)
        {
            if (string.IsNullOrEmpty(request.FileData))
            {
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "文件数据必填", "FileData必填");
            }

            var parts = request.FileData.Split(',');
            if (parts.Length!=2)
            {
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "文件数据无效", "FileData无效");
            }

            var items = new List<BookmarkItem>();
            var bytes = Convert.FromBase64String(parts[1]);
            var content = Encoding.UTF8.GetString(bytes);
            var rgx = new Regex("<A(.+)>(.+)</A>", RegexOptions.Multiline);
            var ms = rgx.Matches(content);
            if (ms.Count>0)
            {
                foreach (Match m in ms)
                {
                    if (m.Success && m.Groups.Count>=3)
                    {
                        var attr = m.Groups[1].Value;
                        var title = m.Groups[2].Value;
                        var item = new BookmarkItem
                        {
                            Id = RandomHelper.RequestId(),
                            Title = title,
                            Url = GetAttr(attr, "HREF"),
                            CreatedAt = GetAttr(attr, "ADD_DATE"),
                            Icon = GetAttr(attr, "ICON")
                        };
                        if (string.IsNullOrEmpty(item.CreatedAt))
                        {
                            item.CreatedAt= DateTimeHelper.GetTimeStamp().ToString();
                        }
                        items.Add(item);
                    }
                }
            }
            AddBookmarks(items.ToArray());
            SaveBookmarks();
            return $"导入成功{items.Count}个书签";
        }

        private string GetAttr(string attr, string name)
        {
            var parts = attr.Split(name);
            if (parts.Length>1)
            {
                var idx1 = parts[1].IndexOf("\"");
                if (idx1 >= 0)
                {
                    var idx2 = parts[1].IndexOf("\"", idx1 + 1);
                    if (idx2 >= 0)
                    {
                        return parts[1].Substring(idx1 + 1, idx2 - idx1 - 1);
                    }
                }
            }
            return "";
        }

        private DownloadRequest Export(string WWWRoot)
        {
            if (Bookmarks==null||Bookmarks.Count==0)
            {
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, $"导出失败，请先导入书签");
            }

            var bookmarksTemplateFileName = "bookmarks.html";
            var bookmarksTemplateFullName = Path.Combine(WWWRoot, bookmarksTemplateFileName);
            if (!File.Exists(bookmarksTemplateFullName))
            {
                throw new WithCodeException((int)ErrorCodeEnum.CodeError, $"导出失败，书签模板文件不存在", "bookmarks.html不存在");
            }

            var template = File.ReadAllText(bookmarksTemplateFullName, Encoding.UTF8);
            var module = "Bookmarks";
            var exportFolder = Path.Combine(WWWRoot, "Exports", module);
            if (!Directory.Exists(exportFolder))
            {
                Directory.CreateDirectory(exportFolder);
            }

            var exportFileName = $"Bookmarks{RandomHelper.RequestId()}.html";
            var exportFullName = Path.Combine(exportFolder, exportFileName);
            var sb = new StringBuilder();
            foreach (var item in Bookmarks)
            {
                sb.AppendLine($"<DT><A HREF=\"{item.Url}\" ADD_DATE=\"{item.CreatedAt}\" ICON=\"{item.Icon}\">{item.Title}</A>");
            }

            template = template.Replace("@@(createdat)", DateTimeHelper.GetTimeStamp().ToString());
            template = template.Replace("@@(bookmarks)", sb.ToString());

            File.WriteAllText(exportFullName, template, Encoding.UTF8);
            return new DownloadRequest
            {
                Module=module,
                FileName=exportFileName
            };
        }

        private List<BookmarkItem> GetBookmarks(GetBookmarksRequest request)
        {
            if (_bookmarks == null)
            {
                _bookmarks = new List<BookmarkItem>();
                LoadBookmarks();
            }

            return Bookmarks;
        }

        private string DeleteBookmarks(DeleteBookmarksRequest request)
        {
            var ids = CollectionHelper.GetIds<string>(request.Ids);
            if (ids.Count == 0)
            {
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, "请选择要删除的书签", "Ids必填");
            }

            foreach (var id in ids)
            {
                for (var i = Bookmarks.Count -1; i>=0; i--)
                {
                    var item = Bookmarks[i];
                    if (item.Id == id)
                    {
                        Bookmarks.RemoveAt(i);
                    }
                }
            }
            SaveBookmarks();
            return $"删除成功{ids.Count}个书签";
        }

        private static List<BookmarkItem> _bookmarks;

        private static List<BookmarkItem> Bookmarks
        {
            get
            {
                if (_bookmarks == null)
                {
                    _bookmarks = new List<BookmarkItem>();
                }

                return _bookmarks;
            }
        }

        private static void LoadBookmarks()
        {
            var fileName = "bookmarks.json";
            if (!File.Exists(fileName))
            {
                throw new WithCodeException((int)ErrorCodeEnum.InvalidArguments, $"bookmarks.json不存在，请重新导入书签");
            }

            var content = File.ReadAllText(fileName, Encoding.UTF8);
            var items = SerializationHelper.ParseFromJson<List<BookmarkItem>>(content);
            if (items != null)
            {
                _bookmarks = items;
            }
        }

        private static void SaveBookmarks()
        {
            var fileName = "bookmarks.json";
            var json = SerializationHelper.ToJson(Bookmarks);
            File.WriteAllText(fileName, json, Encoding.UTF8);
        }

        private static void AddBookmarks(params BookmarkItem[] items)
        {
            Bookmarks.AddRange(items);
        }

        private string DeleteInvalids(DeleteBookmarksRequest request)
        {
            var ids = CollectionHelper.GetIds<string>(request.Ids);
            if (ids.Count == 0)
            {
                ids = Bookmarks.Where(w => w.Status == (int)StatusEnum.Invalid).Select(o => o.Id).ToList();
            }

            foreach (var id in ids)
            {
                for (var i = Bookmarks.Count -1; i>=0; i--)
                {
                    var item = Bookmarks[i];
                    if (item.Id == id)
                    {
                        Bookmarks.RemoveAt(i);
                    }
                }
            }
            SaveBookmarks();
            return $"删除成功{ids.Count()}个无效书签";
        }
        
        private string DeleteDuplicate()
        {
            var sum = 0;
            var items = new List<BookmarkItem>();
            var groups = Bookmarks.GroupBy(g => g.Url);
            foreach (var group in groups)
            {
                if (group.Count()>1)
                {
                    sum+=1;
                }

                items.Add(group.FirstOrDefault());
            }
            _bookmarks = items;
            SaveBookmarks();
            return $"去除了{sum}个重复的书签";
        }

        private string Refresh(DeleteBookmarksRequest request)
        {
            var ids = CollectionHelper.GetIds<string>(request.Ids);
            foreach (var item in Bookmarks)
            {
                if (ids.Count > 0 && ids.Contains(item.Id) == false)
                {
                    continue;
                }

                item.Status = (int)StatusEnum.Checking;
            }

            TaskHelper.RunUseThread(() =>
            {
                CheckBookmarks(ids.ToArray());
            });
            return $"检测耗时较长，将在后台进行，你可以刷新列表查看检测进度。请不要频繁点击检测。";
        }

        private string Reset(DeleteBookmarksRequest request)
        {
            var ids = CollectionHelper.GetIds<string>(request.Ids);
            foreach (var item in Bookmarks)
            {
                if (ids.Count > 0 && ids.Contains(item.Id) == false)
                {
                    continue;
                }

                item.Status = null;
            }
            SaveBookmarks();
            return $"已重置{Bookmarks.Count}个书签状态为【未检测】";
        }

        private void CheckBookmarks(params string[] ids)
        {
            var titleRgx = new Regex("<title>(.+)</title>");
            foreach (var item in Bookmarks)
            {
                if (ids.Length > 0 && ids.Contains(item.Id) == false)
                {
                    continue;
                }

                if (item.Status != (int)StatusEnum.Checking)
                {
                    continue;
                }

                if (string.IsNullOrEmpty(item.Url))
                {
                    item.Status = (int)StatusEnum.Invalid;
                    item.LastUpdatedAt = DateTime.Now;
                    continue;
                }

                try
                {
                    var bytes = HttpHelper.Download(item.Url);
                    var html = Encoding.UTF8.GetString(bytes);
                    var m = titleRgx.Match(html);
                    if (m.Success && m.Groups.Count>1)
                    {
                        item.Title = m.Groups[1].Value;
                    }
                    item.Status = (int)StatusEnum.Valid;
                    item.LastUpdatedAt = DateTime.Now;
                }
                catch
                {
                    item.Status = (int)StatusEnum.Invalid;
                }

                try
                {
                    var schema = "";
                    var host = item.Url;
                    var idx = host.IndexOf("://");
                    if (idx >= 0)
                    {
                        schema = host.Substring(0, idx) + "://";
                        host = host.Substring(idx + 3);
                    }

                    var idx2 = host.IndexOf("/");
                    if (idx2 >= 0)
                    {
                        host = host.Substring(0, idx2);
                    }

                    var url = $"{schema}{host}/favicon.ico";
                    var icon = HttpHelper.Download(url);
                    var base64string = Convert.ToBase64String(icon);
                    item.Icon = $"data:image/x-icon;base64,{base64string}";
                }
                catch
                {
                }
            }
            SaveBookmarks();
        }
    }
}

/// <summary>
/// 状态 null=未检测，1=检测中，2=有效，3=无效
/// </summary>
public enum StatusEnum
{
    None = 0,

    /// <summary>
    /// 检测中
    /// </summary>
    Checking = 1,

    /// <summary>
    /// 有效
    /// </summary>
    Valid = 2,

    /// <summary>
    /// 无效
    /// </summary>
    Invalid = 3,
}

/// <summary>
/// 书签
/// </summary>
public class BookmarkItem
{
    /// <summary>
    /// 唯一编号
    /// </summary>
    public string Id { get; set; }

    /// <summary>
    /// 图标
    /// </summary>
    public string Icon { get; set; }

    /// <summary>
    /// 标题
    /// </summary>
    public string Title { get; set; }

    /// <summary>
    /// 地址
    /// </summary>
    public string Url { get; set; }

    /// <summary>
    /// 创建时间
    /// </summary>
    public string CreatedAt { get; set; }

    /// <summary>
    /// 状态 null=未检测，1=检测中，2=有效，3=无效
    /// </summary>
    public int? Status { get; set; }

    /// <summary>
    /// 最后更新时间
    /// </summary>
    public DateTime? LastUpdatedAt { get; set; }
}

public class ImportRequest
{
    /// <summary>
    /// 文件名
    /// </summary>
    public string FileName { get; set; }

    /// <summary>
    /// 文件数据
    /// </summary>
    public string FileData { get; set; }
}

public class DownloadRequest
{
    public string Module { get; set; }

    public string FileName { get; set; }
}

public class GetBookmarksRequest
{

}

public class DeleteBookmarksRequest
{
    public string Ids { get; set; }
}